import {
  CSSProperties,
  SetupContext,
  ShallowRef,
  computed,
  nextTick,
  ref,
  shallowRef,
  useId,
} from 'vue';
import {
  Button,
  Card,
  CardProps,
  ConfigProvider,
  type FormProps,
  Modal,
  Space,
  message,
} from 'ant-design-vue';
import { useRequest } from 'vue-request';
import { JSX } from 'vue/jsx-runtime';
import { ProForm, ProFormProps } from '@/components/ProForm/index';
import { borderStyle } from '@/constant/theme';

export namespace UseFormModal {
  export interface Tabs {
    tab: string;
    key: string;
    items: ProFormProps['items'];
    [key: string]: any;
  }

  export type Props = {
    getContainer?:
      | string
      | false
      | HTMLElement
      | (() => HTMLElement)
      | undefined;
    items?: ProFormProps['items'];
    tabs?: Tabs[];
    wrapClassName?: string;
  };

  export type ModalType = 'info' | 'add' | 'edit' | 'disabled';

  export interface Options {
    column?: 1 | 2 | 3;
    size?: 'large' | 'middle' | 'small' | 'mini';
    formProps?: FormProps;
    bodyHeight?: number;
    onValuesChange?: (
      changeValues: Record<string, any>,
      formState: Record<string, any>,
      modalType: ModalType,
    ) => void;
  }

  export interface OpenParams {
    title?: string | ((modalType: ModalType) => string);
    serviceApi: (params: any) => Promise<any>;
    defaultValue?: Record<string, unknown>;
    content?: string;
    modalType?: ModalType;
    items?: Props['items'];
    size?: Options['size'];
    column?: Options['column'];
    hasEditPermission?: boolean;
    hideFooter?: boolean;
    onChangeModeType?: (modalType: ModalType) => void;
  }

  export interface Res {
    open: (params: OpenParams) => void;
    FormModal: (props: Props, ctx: SetupContext) => JSX.Element;
    formRef: ShallowRef;
    actualHeight: ShallowRef;
  }

  export interface UseFormModal {
    (options: Options): Res;
  }
}

const widthMap: Map<UseFormModal.Options['size'], number> = new Map([
  ['large', 1600],
  ['middle', 1200],
  ['small', 700],
  ['mini', 400],
]);

export const useFormModal: UseFormModal.UseFormModal = (options = {}) => {
  const visible = ref(false);
  const formRef = shallowRef();
  const modalType = ref<UseFormModal.ModalType>('add');
  const readonly = computed(() =>
    ['info', 'disabled'].includes(modalType.value),
  );

  const width = computed(() => {
    return widthMap.get(size.value || options.size || 'middle');
  });
  const formColLayout = computed(() => {
    const num = 24 / (column.value || options.column || 1);
    return { xs: num, sm: num, md: num, lg: num };
  });
  const bodyHeight = ref(options.bodyHeight || 0);

  const formProps = computed<ProFormProps>(() => {
    return {
      labelAlign: 'right',
      labelCol: { span: 4 },
      wrapperCol: { span: 20 },
      ...(options.formProps || {}),
    };
  });
  const formState = ref<Record<string, any>>({});
  const title = ref<UseFormModal.OpenParams['title']>('');
  const modalTitle = computed(() => {
    if (typeof title.value === 'function') {
      return title.value(modalType.value);
    } else {
      return title.value;
    }
  });
  let onChangeModeType: UseFormModal.OpenParams['onChangeModeType'];

  let serviceApi: UseFormModal.OpenParams['serviceApi'] = () =>
    Promise.reject('请传入请求函数');

  const service = (params: any) => {
    return serviceApi(params);
  };
  const { loading, runAsync } = useRequest(service, {
    manual: true,
    debounceInterval: 500,
  });
  const content = ref('');
  const smallItems = shallowRef<UseFormModal.Props['items']>([]);
  const size = ref<UseFormModal.OpenParams['size']>();
  const column = ref<UseFormModal.OpenParams['column']>();

  const hasEditPermission = ref(true);

  const hideFooter = ref(false);

  const currentId = ref('');
  const actualHeight = ref();
  const open = (params: UseFormModal.OpenParams) => {
    currentId.value = `model-${Math.random().toString().slice(-6)}`;

    title.value = params.title ?? '';
    modalType.value = params.modalType || 'add';
    formState.value = params.defaultValue || {};
    currentIndex.value = 0;
    content.value = params.content || '';
    smallItems.value = params.items || [];
    params.size && (size.value = params.size);
    params.column && (column.value = params.column);
    hasEditPermission.value = params.hasEditPermission ?? true;
    hideFooter.value = params.hideFooter ?? false;
    onChangeModeType = params.onChangeModeType;
    serviceApi = params.serviceApi;
    visible.value = true;
    nextTick(() => {
      console.log(currentId.value, 'currentId');
      const dom = document.querySelector(`.${currentId.value} .ant-modal-body`);
      actualHeight.value = dom?.clientHeight;
      console.log(dom?.clientHeight, '计算高度');
    });
  };

  const currentIndex = ref(0);

  const submit = async () => {
    try {
      const state = await formRef.value.validate();
      formState.value = {
        ...formState.value,
        ...state,
      };

      await runAsync(formState.value);
      visible.value = false;
      message.success('操作成功');
    } catch (error) {
      console.error(error);
    }
  };

  const next = async (tabs: UseFormModal.Props['tabs']) => {
    try {
      const state = await formRef.value.validate();
      formState.value = {
        ...formState.value,
        ...state,
      };
      if (currentIndex.value === tabs!.length - 1) {
        return;
      }
      currentIndex.value++;
    } catch (error) {
      console.error(error);
    }
  };

  const prev = () => {
    if (currentIndex.value === 0) return;
    currentIndex.value--;
  };
  const onEdit = () => {
    modalType.value = 'edit';
    onChangeModeType?.(modalType.value);
  };

  const onCancel = () => {
    if (modalType.value === 'add') {
      visible.value = false;
      return;
    }
    if (modalType.value === 'edit') {
      modalType.value = 'info';
    }
    onChangeModeType?.(modalType.value);
    formRef.value.clearValidate();
    formRef.value.resetFields();
  };

  const FormModal: UseFormModal.Res['FormModal'] = (props, { slots }) => {
    const { 'after-content': afterContent, customFooter, ..._slots } = slots;

    const modelFooter = () => {
      if (hideFooter.value) return null;

      if (customFooter) {
        return customFooter({
          modalType,
          formState: formState.value,
          visible,
        });
      }

      if (modalType.value === 'disabled' || !hasEditPermission.value) {
        return (
          // <Button type='primary' onClick={() => (visible.value = false)}>
          //   关闭
          // </Button>
          <></>
        );
      }

      if (modalType.value === 'info') {
        return <Button onClick={onEdit}>编辑</Button>;
      }

      const type =
        props.tabs?.length === 0
          ? 'submit'
          : props.tabs?.length && currentIndex.value !== props.tabs.length - 1
            ? 'next'
            : 'submit';
      return (
        <Space>
          {currentIndex.value !== 0 && (
            <Button onClick={() => prev()}>上一步</Button>
          )}
          {type === 'next' ? (
            <>
              <Button onClick={() => next(props.tabs)}>下一步</Button>
            </>
          ) : (
            <Button
              type='primary'
              loading={loading.value}
              onClick={() => submit()}
            >
              确认
            </Button>
          )}
          <Button onClick={() => onCancel()}>取消</Button>
        </Space>
      );
    };

    const currentTable =
      props.tabs?.length && props.tabs[currentIndex.value].key;

    const Container = (_props: any, { slots, emit }: SetupContext) => {
      if (props.tabs?.length) {
        return (
          <Card
            class='form-modal'
            tabList={props.tabs || []}
            style={{ border: 0 }}
            activeTabKey={currentTable || ''}
            onTabChange={(key) => emit('tableChange', key)}
            {..._props}
          >
            {{ ...slots }}
          </Card>
        );
      } else {
        return <>{slots.default ? slots.default() : null}</>;
      }
    };

    const items = () => {
      if (props.tabs?.length) {
        return props.tabs[currentIndex.value].items;
      } else {
        return props.items || [];
      }
    };

    const cardProps = (): CardProps => {
      if (props.tabs?.length) {
        const bodyStyle: CardProps['bodyStyle'] = {
          paddingLeft: 0,
          paddingRight: 0,
        };
        if (bodyHeight.value) {
          Object.assign(bodyStyle, {
            height: `${bodyHeight.value}px`,
            overflowY: 'auto',
          });
        }
        return {
          bodyStyle,
        };
      }
      return {};
    };

    const onValuesChange = (
      values: Record<string, any>,
      state: Record<string, any>,
    ) => {
      formState.value = {
        ...formState.value,
        ...state,
      };
      options.onValuesChange?.(values, state, modalType.value);
    };

    const onTableChange = (key: string) => {
      if (!['info', 'disabled'].includes(modalType.value)) return;
      const index = props.tabs?.findIndex((item) => item.key === key);
      currentIndex.value = index!;
    };

    return (
      <ConfigProvider
        theme={{
          components: {
            Tabs: {
              lineWidth: 0,
            },
            Input: borderStyle,
            Select: borderStyle,
            InputNumber: borderStyle,
          },
        }}
      >
        <Modal
          wrapClassName={props.wrapClassName}
          class={currentId.value}
          title={modalTitle.value}
          open={visible.value}
          width={width.value}
          footer={modelFooter()}
          onCancel={() => (visible.value = false)}
          maskClosable={false}
          keyboard={false}
          destroyOnClose
          centered
          getContainer={props.getContainer}
        >
          <Container
            {...cardProps()}
            onTableChange={(key: string) => {
              onTableChange(key);
            }}
          >
            <div class='content-wrap'>{content.value || ''}</div>
            <ProForm
              ref={formRef}
              model={formState.value}
              items={smallItems.value?.length ? smallItems.value : items()}
              {...formProps.value}
              disabled={readonly.value}
              onValuesChange={onValuesChange}
              formColLayout={formColLayout.value}
              requiredMark={!readonly.value}
              class='pro-form-modal'
              modalType={modalType.value}
            >
              {{
                ..._slots,
              }}
            </ProForm>
            {afterContent?.({
              modalType,
              formState: formState.value,
              visible,
            })}
          </Container>
        </Modal>
      </ConfigProvider>
    );
  };

  return {
    open,
    FormModal,
    formRef,
    actualHeight,
  };
};
